Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow to restrict floodfill to a bounding box #8267

Open
wants to merge 25 commits into
base: master
Choose a base branch
from

Conversation

philippotto
Copy link
Member

@philippotto philippotto commented Dec 9, 2024

URL of deployed dev instance (used for testing):

  • https://___.webknossos.xyz

Steps to test:

  • check out the new toggle in the tool bar when the floodfill tool is selected
    image
  • when disabled, the flood fill should behave almost as usual
    • one change is that if it terminates early, it should create a new bounding box only if in 3D mode
  • when enabled, the flood fill operation will be constrained to the bbox that encloses the clicked position. if there is none, a toast should appear

TODOs:

Issues:


(Please delete unneeded items, merge only when none are left open)

@philippotto philippotto self-assigned this Dec 9, 2024
Copy link
Contributor

coderabbitai bot commented Dec 9, 2024

📝 Walkthrough
📝 Walkthrough

Walkthrough

This pull request introduces a new feature allowing the flood fill tool to be restricted to a specified bounding box. The changes span multiple files in the frontend, adding a toggle in the toolbar to enable bounding box restriction for flood fill operations. A new constant and configuration option have been added to manage this functionality, with modifications to the flood fill saga and data cube handling to support the restricted fill mode. The implementation ensures that flood fill operations can be constrained within user-defined or automatically generated bounding boxes.

Changes

File Change Summary
frontend/javascripts/oxalis/store.ts Added isFloodfillRestrictedToBoundingBox to UserConfiguration type
frontend/javascripts/oxalis/default_state.ts Added isFloodfillRestrictedToBoundingBox: false to default user configuration
frontend/javascripts/oxalis/constants.ts Added FLOOD_FILL_MULTIPLIER_FOR_BBOX_RESTRICTION constant
frontend/javascripts/oxalis/view/action-bar/toolbar_view.tsx Introduced FloodFillSettings component with bounding box restriction toggle
frontend/javascripts/oxalis/model/sagas/volume/floodfill_saga.tsx New saga for handling bounding box-restricted flood fill
frontend/javascripts/oxalis/model/bucket_data_handling/data_cube.ts Updated floodFill method to respect bounding box restrictions

Assessment against linked issues

Objective Addressed Explanation
Allow fill tool restriction to bbox Implemented toggle and bounding box selection mechanism
Enable bbox restriction in toolbar Added FloodFillSettings component with boolean toggle
Support dropdown for enclosing bbox Partial implementation, may require further refinement

Possibly related PRs

Suggested labels

enhancement, frontend

Suggested reviewers

  • MichaelBuessemeyer
  • daniel-wer

Poem

🐰 A Rabbit's Flood Fill Delight
With bounding boxes tight and bright,
Our fill tool dances, precise and light,
Restricted zones now come to play,
Segmenting data the smarter way!
🎨✨

Tip

CodeRabbit's docstrings feature is now available as part of our Early Access Program! Simply use the command @coderabbitai generate docstrings to have CodeRabbit automatically generate docstrings for your pull request. We would love to hear your feedback on Discord.


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@philippotto philippotto changed the title [WIP] Allow to restrict floodfill to a bounding box Allow to restrict floodfill to a bounding box Dec 17, 2024
@philippotto philippotto marked this pull request as ready for review December 17, 2024 15:36
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (9)
frontend/javascripts/oxalis/model/sagas/volume/floodfill_saga.tsx (1)

35-102: Ensure proper handling of failure reasons in getBoundingBoxForFloodFill

In the getBoundingBoxForFloodFill function, when returning failure reasons, ensure that the failure messages are user-friendly and informative. This will enhance the user's understanding when the flood fill operation cannot proceed.

frontend/javascripts/test/sagas/volumetracing/volumetracing_saga_integration.spec.ts (1)

Line range hint 330-347: Improve test reliability with explicit undo actions

When performing undo and redo operations in the test, ensure that each action is awaited properly to prevent race conditions and enhance test stability.

Apply this diff to await undo and redo actions explicitly:

- await dispatchUndoAsync(Store.dispatch);
+ await dispatchUndoAsync(Store.dispatch);
+ await t.context.api.tracing.save();

- await dispatchRedoAsync(Store.dispatch);
+ await dispatchRedoAsync(Store.dispatch);
+ await t.context.api.tracing.save();
frontend/stylesheets/trace_view/_action_bar.less (1)

71-74: Consider using a more semantic class name

The class name .undo-redo-button suggests specific usage, but the functionality (preventing width flickering) could be useful for other buttons. Consider a more generic name like .fixed-width-button or .no-flicker-button.

CHANGELOG.unreleased.md (1)

16-16: Enhance the changelog entry with more details

Consider expanding the changelog entry to provide more comprehensive information about the feature:

-The fill tool can now be adapted so that it only acts within a specified bounding box. Use the new "Restrict Floodfill" mode for that in the toolbar. [#8267](https://github.com/scalableminds/webknossos/pull/8267)
+The fill tool can now be restricted to operate within a specified bounding box. Enable the new "Restrict Floodfill" toggle in the toolbar when the fill tool is selected. If no bounding box exists when using this mode, a notification will be displayed. This feature helps prevent unintended fill operations outside the area of interest. [#8267](https://github.com/scalableminds/webknossos/pull/8267)
frontend/javascripts/oxalis/default_state.ts (1)

87-87: LGTM! Consider adding JSDoc

The new configuration property is well-named and appropriately placed. Consider adding JSDoc documentation to describe its purpose and behavior:

+    /** When enabled, restricts flood fill operations to the current bounding box */
     isFloodfillRestrictedToBoundingBox: false,
frontend/javascripts/oxalis/constants.ts (1)

336-338: Consider adding more detailed documentation.

While the comment explains the purpose, it would be helpful to document:

  1. Why the value of 10 was chosen
  2. What "more lax" means in terms of actual behavior
  3. The impact on performance and memory usage
frontend/javascripts/oxalis/model/bucket_data_handling/data_cube.ts (2)

501-509: Consider adding more detailed documentation for the dynamic bounding box expansion

While the implementation is solid, the comment could be more explicit about:

  • The purpose of allowing multiple additions of the same bucket
  • The implications of the "neighbour volume shape" concept
  • How this relates to the new bounding box restriction feature

695-724: Consider enhancing the progress logging

The progress logging implementation could be improved:

  1. Consider using a constant for the progress update interval (1000000)
  2. Consider adding an estimate of total progress (e.g., percentage complete)
  3. Consider adding more context about the operation in the progress message
-                if (labeledVoxelCount % 1000000 === 0) {
-                  console.log(`Labeled ${labeledVoxelCount} Vx. Continuing...`);
-
-                  await progressCallback(
-                    false,
-                    `Labeled ${labeledVoxelCount / 1000000} MVx. Continuing...`,
-                  );
+                const PROGRESS_UPDATE_INTERVAL = 1000000;
+                if (labeledVoxelCount % PROGRESS_UPDATE_INTERVAL === 0) {
+                  const message = `Flood fill: Labeled ${(labeledVoxelCount / 1000000).toFixed(1)} MVx`;
+                  console.log(message);
+                  await progressCallback(false, message);
frontend/javascripts/oxalis/view/action-bar/toolbar_view.tsx (1)

1372-1405: Consider enhancing the FloodFillSettings component

While the implementation is solid, consider these improvements:

  1. Extract the tooltip text to a constant for reusability
  2. Add a data-testid attribute for easier testing
  3. Consider using a memo hook for the toggle callback to prevent unnecessary re-renders
+const FLOOD_FILL_BBOX_TOOLTIP = 
+  "When enabled, the floodfill will be restricted to the bounding box enclosed by the clicked position. If multiple bounding boxes enclose that position, the smallest is used.";

 function FloodFillSettings() {
   const dispatch = useDispatch();
   const isRestrictedToBoundingBox = useSelector(
     (state: OxalisState) => state.userConfiguration.isFloodfillRestrictedToBoundingBox,
   );
-  const toggleRestrictFloodfillToBoundingBox = () => {
+  const toggleRestrictFloodfillToBoundingBox = useCallback(() => {
     dispatch(
       updateUserSettingAction("isFloodfillRestrictedToBoundingBox", !isRestrictedToBoundingBox),
     );
-  };
+  }, [dispatch, isRestrictedToBoundingBox]);

   return (
-    <div>
+    <div data-testid="flood-fill-settings">
       <FillModeSwitch />

       <ButtonComponent
         style={{
           opacity: isRestrictedToBoundingBox ? 1 : 0.5,
           marginLeft: 12,
         }}
         type={isRestrictedToBoundingBox ? "primary" : "default"}
         onClick={toggleRestrictFloodfillToBoundingBox}
-        title={
-          "When enabled, the floodfill will be restricted to the bounding box enclosed by the clicked position. If multiple bounding boxes enclose that position, the smallest is used."
-        }
+        title={FLOOD_FILL_BBOX_TOOLTIP}
       >
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cc75b60 and 637ce46.

⛔ Files ignored due to path filters (1)
  • public/images/icon-restrict-floodfill-to-bbox.svg is excluded by !**/*.svg
📒 Files selected for processing (18)
  • CHANGELOG.unreleased.md (1 hunks)
  • frontend/javascripts/components/async_clickables.tsx (2 hunks)
  • frontend/javascripts/libs/mjs.ts (1 hunks)
  • frontend/javascripts/oxalis/constants.ts (1 hunks)
  • frontend/javascripts/oxalis/controller/combinations/bounding_box_handlers.ts (1 hunks)
  • frontend/javascripts/oxalis/default_state.ts (1 hunks)
  • frontend/javascripts/oxalis/model/accessors/tracing_accessor.ts (2 hunks)
  • frontend/javascripts/oxalis/model/bucket_data_handling/bucket.ts (2 hunks)
  • frontend/javascripts/oxalis/model/bucket_data_handling/data_cube.ts (4 hunks)
  • frontend/javascripts/oxalis/model/sagas/volume/floodfill_saga.tsx (1 hunks)
  • frontend/javascripts/oxalis/model/sagas/volumetracing_saga.tsx (3 hunks)
  • frontend/javascripts/oxalis/store.ts (1 hunks)
  • frontend/javascripts/oxalis/view/action-bar/toolbar_view.tsx (2 hunks)
  • frontend/javascripts/oxalis/view/action-bar/tracing_actions_view.tsx (2 hunks)
  • frontend/javascripts/oxalis/view/context_menu.tsx (3 hunks)
  • frontend/javascripts/test/sagas/volumetracing/volumetracing_saga_integration.spec.ts (4 hunks)
  • frontend/stylesheets/trace_view/_action_bar.less (1 hunks)
  • tools/test.sh (1 hunks)
🧰 Additional context used
📓 Learnings (1)
frontend/javascripts/oxalis/model/sagas/volumetracing_saga.tsx (1)
Learnt from: dieknolle3333
PR: scalableminds/webknossos#8168
File: frontend/javascripts/oxalis/model/sagas/volumetracing_saga.tsx:433-434
Timestamp: 2024-11-22T17:19:07.947Z
Learning: In the codebase, certain usages of `segmentationLayer.resolutions` are intentionally retained and should not be changed to `segmentationLayer.mags` during refactoring.
🔇 Additional comments (13)
frontend/javascripts/oxalis/model/sagas/volumetracing_saga.tsx (1)

13-13: ⚠️ Potential issue

Retain usage of segmentationLayer.resolutions where necessary

According to previous learnings, certain usages of segmentationLayer.resolutions should not be replaced with segmentationLayer.mags. Please verify that all such intentional usages remain unchanged.

Run the following script to identify unintended replacements:

frontend/javascripts/test/sagas/volumetracing/volumetracing_saga_integration.spec.ts (1)

Line range hint 277-305: Ensure consistent use of EXPECTED_HALF_EXTENT in tests

In the new test case, EXPECTED_HALF_EXTENT is calculated using Constants.FLOOD_FILL_EXTENTS. Verify that this matches the actual extents used in the flood fill operation to ensure the test accurately reflects the behavior.

frontend/javascripts/components/async_clickables.tsx (1)

50-55: LGTM! Good UX improvement

The addition of ConfigProvider to disable motion effects is a clean solution to prevent jarring animations during icon swaps.

frontend/javascripts/oxalis/model/accessors/tracing_accessor.ts (2)

91-95: LGTM! Robust null handling

The function safely handles the case where tracing might be null by leveraging the existing maybeGetSomeTracing helper.


97-104: Consider memoizing the BoundingBox instances

Creating new BoundingBox instances on every filter iteration could be inefficient for large numbers of boxes. Consider transforming the bounding boxes into BoundingBox instances once, then reusing them.

 export const getUserBoundingBoxesThatContainPosition = (
   state: OxalisState,
   position: Vector3,
 ): Array<UserBoundingBox> => {
   const bboxes = getUserBoundingBoxesFromState(state);
+  const boundingBoxInstances = bboxes.map(
+    (el) => new BoundingBox(el.boundingBox)
+  );
 
-  return bboxes.filter((el) => new BoundingBox(el.boundingBox).containsPoint(position));
+  return bboxes.filter((_, idx) => 
+    boundingBoxInstances[idx].containsPoint(position)
+  );
 };

Let's verify the BoundingBox implementation:

tools/test.sh (1)

93-93: LGTM! Improved test file filtering

The addition of grep -E -v "\.(md|snap)" correctly excludes markdown and snapshot files from the test execution, making the test runs more focused and efficient.

frontend/javascripts/libs/mjs.ts (1)

253-255: LGTM: Simple and correct implementation of vector product.

The prod method correctly calculates the product of vector components, which is useful for computing areas (V2) or volumes (V3).

frontend/javascripts/oxalis/controller/combinations/bounding_box_handlers.ts (1)

245-247: LGTM: Good type safety improvement.

The explicit third argument to V3.add ensures a Vector3 is returned instead of Float32Array, making the code more type-safe.

frontend/javascripts/oxalis/store.ts (1)

397-397: LGTM: Clean addition of flood fill restriction configuration

The new boolean property isFloodfillRestrictedToBoundingBox is properly typed and well-placed within the UserConfiguration interface.

frontend/javascripts/oxalis/view/action-bar/tracing_actions_view.tsx (1)

Line range hint 499-507: LGTM: Improved button styling consistency

The addition of the 'undo-redo-button' class to both undo and redo buttons helps prevent width flickering. The 'hide-on-small-screen' class on the redo button maintains proper responsive behavior.

Also applies to: 509-517

frontend/javascripts/oxalis/model/bucket_data_handling/bucket.ts (2)

42-45: LGTM: Well-implemented throttled warning

The new warning function follows the established pattern of throttled warnings and helps prevent warning spam while maintaining error visibility.


780-780: LGTM: Improved error handling consistency

Good replacement of direct warning with the throttled version, maintaining functionality while improving error handling consistency.

frontend/javascripts/oxalis/model/bucket_data_handling/data_cube.ts (1)

490-491: LGTM: Good use of BoundingBox class for type safety

The parameter renaming and wrapping in BoundingBox class is a good practice that provides type safety and maintainability.

Also applies to: 510-511

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
docs/volume_annotation/tools.md (1)

71-72: Enhance the documentation with additional implementation details.

The documentation provides a good overview of the new feature, but could be enhanced with the following details from the PR objectives:

  1. Clarify the toggle behavior:
    • When disabled: Flood fill operates normally
    • When enabled: Fill is limited to the bounding box
  2. Add a note about the notification shown when no bounding box exists
  3. Explain the 3D mode behavior regarding early termination and bounding box creation

Consider expanding the section with this additional content:

 ![Restrict Fill](./images/icon_restricted_floodfill.jpg){align=left width="60"} 
 **Restrict Fill by Bounding Box**: When enabled, the fill operation will be restricted by the smallest bounding box that encloses the clicked position. This feature can be useful when correcting segmentation in a small bounding box (e.g., when curating training data).
+
+When the toggle is disabled, flood fill operates normally. When enabled, the fill will be limited to the bounding box encompassing the clicked position. If no bounding box exists, you'll receive a notification. In 3D mode, a new bounding box will only be created on early termination if the restriction is disabled.
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 637ce46 and 3959e9b.

⛔ Files ignored due to path filters (1)
  • docs/images/icon_restricted_floodfill.jpg is excluded by !**/*.jpg
📒 Files selected for processing (1)
  • docs/volume_annotation/tools.md (1 hunks)

…ple floodfills; also don't show bbox message if floodfill was constraint to bbox
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
frontend/javascripts/oxalis/model/sagas/volume/floodfill_saga.tsx (2)

53-54: Consider extracting repeated volume calculation logic into a helper function.

Here, you use new BoundingBox(bbox.boundingBox).getVolume() while also using a similar logic for 2D calculations below. Factoring out this logic would reduce duplication and improve readability.


69-72: Provide localized or more concise error messaging if needed.

The error message might be displayed to end-users verbatim. If you plan to support multiple languages or wish to keep messages more concise, consider externalizing or simplifying the string.

frontend/javascripts/libs/progress_callback.ts (1)

14-14: Document the final feedback method parameter.

The “finalFeedbackMethod” is intuitive, but consider adding a brief line in the code comments about acceptable values (“success”, “error”, “info”, “warning”) for self-documentation.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3959e9b and d13abc2.

📒 Files selected for processing (2)
  • frontend/javascripts/libs/progress_callback.ts (2 hunks)
  • frontend/javascripts/oxalis/model/sagas/volume/floodfill_saga.tsx (1 hunks)
🔇 Additional comments (4)
frontend/javascripts/oxalis/model/sagas/volume/floodfill_saga.tsx (3)

106-110: Clarify concurrency behavior in the while loop.

Using a while loop with yield* take("FLOOD_FILL") may sequentially process requests, but consider explaining or documenting in comments how concurrent flood fill operations should be handled. If concurrency is not intended, ensuring there's only one active flood fill at a time is fine.


153-156: Reminder: Handle potential ongoing operations.

This code checks if the UI is busy, but does not handle an ongoing flood fill. In a previous review comment, concurrency handling was suggested; re-verify if additional checks are needed so that multiple fill operations do not overlap.


190-199: Deferred bounding box creation logic.

When wasBoundingBoxExceeded is true, you handle the special case (line ~257) of skipping bounding box creation in restricted mode. Ensure that you have confirmed this meets the PR’s objective to avoid inadvertently ignoring large bounding boxes in restricted mode.

frontend/javascripts/libs/progress_callback.ts (1)

3-5: Good use of type alias for extensibility.

Defining HideFn as a dedicated type clarifies the code’s intent and will help if you expand these functions later.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
frontend/javascripts/test/sagas/saga_integration.mock.ts (1)

18-21: LGTM! Consider clarifying the comment.

The changes improve the mock's fidelity by returning hide functions, which better matches the actual antd message API behavior.

Consider making the comment more explicit about the API behavior:

-    // These return a "hide function"
+    // These methods return a function that can be called to hide/close the message
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d13abc2 and da9cead.

📒 Files selected for processing (1)
  • frontend/javascripts/test/sagas/saga_integration.mock.ts (1 hunks)

Comment on lines 36 to 51
if (isRestrictedToBoundingBox) {
const bboxes = yield* select((state) =>
getUserBoundingBoxesThatContainPosition(state, position),
);
if (bboxes.length > 0) {
const smallestBbox = _.sortBy(bboxes, (bbox) =>
new BoundingBox(bbox.boundingBox).getVolume(),
)[0];
return smallestBbox.boundingBox;
} else {
return {
failureReason:
"No bounding box encloses the clicked position. Either disable the bounding box restriction or ensure a bounding box exists around the clicked position.",
};
}
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is new

Comment on lines 141 to 144
if ("failureReason" in boundingBoxForFloodFill) {
Toast.warning(boundingBoxForFloodFill.failureReason);
return;
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is new

Comment on lines 35 to 36
//

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
//

Copy link
Member Author

@philippotto philippotto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I commented a bit about what code was moved and what is actually new in the sagas.

(state) => state.userConfiguration.isFloodfillRestrictedToBoundingBox,
);
const fillMode = yield* select((state) => state.userConfiguration.fillMode);
if (isRestrictedToBoundingBox) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this block is new

Comment on lines +167 to +171
if ("failureReason" in boundingBoxForFloodFill) {
Toast.warning(boundingBoxForFloodFill.failureReason, {
key: NO_FLOODFILL_BBOX_TOAST_KEY,
});
continue;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is new


console.timeEnd("applyLabeledVoxelMapToAllMissingMags");

let hideSuccessMsgFnBox: { hideFn: () => void } | undefined;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is new

console.timeEnd("applyLabeledVoxelMapToAllMissingMags");

let hideSuccessMsgFnBox: { hideFn: () => void } | undefined;
if (wasBoundingBoxExceeded) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the logic in this if block was changed in this PR

Comment on lines +309 to +314
const floodfillDuration = performance.now() - startTimeOfFloodfill;
const wasFloodfillQuick = floodfillDuration < NO_SUCCESS_MSG_WHEN_WITHIN_MS;

if (hideSuccessMsgFnBox != null && wasFloodfillQuick) {
hideSuccessMsgFnBox.hideFn();
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is also new

@@ -0,0 +1,323 @@
import { V2, V3 } from "libs/mjs";
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

most of the file content is simply moved from the other saga module.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for extracting this into an own file 🎉 🙏

Copy link
Contributor

@MichaelBuessemeyer MichaelBuessemeyer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, thanks for this PR 🎉 🪣

I left some suggestions. Besides these suggestions the PR looks totally fine to me and also works great. The fast closing in case of a fast floodfill operation is awesome btw :D

Let me know if you want to skip some suggestions so I can rereview / approve

Comment on lines +46 to +79
const bboxes = yield* select((state) =>
getUserBoundingBoxesThatContainPosition(state, position),
);
if (bboxes.length > 0) {
const smallestBbox = _.sortBy(bboxes, (bbox) =>
new BoundingBox(bbox.boundingBox).getVolume(),
)[0];

const maximumVoxelSize =
Constants.FLOOD_FILL_MULTIPLIER_FOR_BBOX_RESTRICTION *
V3.prod(Constants.FLOOD_FILL_EXTENTS[fillMode]);
const bboxObj = new BoundingBox(smallestBbox.boundingBox);

const bboxVolume =
fillMode === FillModeEnum._3D
? bboxObj.getVolume()
: // Only consider the 2D projection of the bounding box onto the current viewport
V2.prod(
Dimensions.getIndices(currentViewport).map(
(idx) => bboxObj.getSize()[idx],
) as Vector2,
);
if (bboxVolume > maximumVoxelSize) {
return {
failureReason: `The bounding box that encloses the clicked position is too large. Shrink its size so that it does not contain more than ${maximumVoxelSize} voxels.`,
};
}
return smallestBbox.boundingBox;
} else {
return {
failureReason:
"No bounding box encloses the clicked position. Either disable the bounding box restriction or ensure a bounding box exists around the clicked position.",
};
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe make this an own method to make the method shorter and less nested? 🤔

Comment on lines +82 to +103
const halfBoundingBoxSizeUVW = V3.scale(Constants.FLOOD_FILL_EXTENTS[fillMode], 0.5);
const currentViewportBounding = {
min: V3.sub(position, halfBoundingBoxSizeUVW),
max: V3.add(position, halfBoundingBoxSizeUVW),
};

if (fillMode === FillModeEnum._2D) {
// Only use current plane
const thirdDimension = Dimensions.thirdDimensionForPlane(currentViewport);
const numberOfSlices = 1;
currentViewportBounding.min[thirdDimension] = position[thirdDimension];
currentViewportBounding.max[thirdDimension] = position[thirdDimension] + numberOfSlices;
}

const datasetBoundingBox = yield* select((state) => getDatasetBoundingBox(state.dataset));
const { min: clippedMin, max: clippedMax } = new BoundingBox(
currentViewportBounding,
).intersectedWith(datasetBoundingBox);
return {
min: clippedMin,
max: clippedMax,
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here as above. This could be extracted into an own method making getBoundingBoxForFloodFill much slimmer and less nested

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But that treatment might also be good for floodFill 🙈

Comment on lines +302 to +307
} else {
hideSuccessMsgFnBox = yield* call(progressCallback, true, "Floodfill done.");
}
} else {
hideSuccessMsgFnBox = yield* call(progressCallback, true, "Floodfill done.");
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this maybe be unified to have less code duplication? Maybe put it into line 313 directly and adjust the if condition in line 312 to something like (!wasBoundingBoxExceeded || isRestrictedToBoundingBox) && wasFloodfillQuick?

@@ -0,0 +1,323 @@
import { V2, V3 } from "libs/mjs";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for extracting this into an own file 🎉 🙏

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice image. But maybe the color bucket as used in the flood fill tool icon would be more consistent instead of a color / water drop 🤔

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file looks unused to me

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Allow to make fill tool restricted to a given bbox
2 participants